/*
    Copyright Nicolas Ronvel 2007
	gulix33xp@yahoo.fr

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Xml;

using SdlDotNet.Graphics;

using BlindShark.Widgets;

namespace BlindShark.GameElements
{
	/// <summary>
	/// A Blind Shark Tracklist
	/// </summary>
	public class Tracklist : IListObject
	{
		#region Variables
		private List<AudioFile> _lsTracks;
		private string _sDescription;
		private string _sTitle;
		private string _sAuthor;
		private string _sFilename;
		private int _iCurrent;
		private bool _bRandomizeChoice;
		
		#endregion
		
		#region Constructors
		/// <summary>
		/// Build an empty Tracklist
		/// </summary>
		public Tracklist()
		{
			ClearTracks();
		}
		#endregion
		
		#region Tracks Management
		/// <summary>
		/// Clear all the tracks from the tracklist
		/// </summary>
		public void ClearTracks()
		{
			_lsTracks = null;
			_iCurrent = -1;
		}
		
		/// <summary>
		/// Load the tracks from the Xml File
		/// </summary>
		public void LoadTracks()
		{
			ClearTracks();
			
			if (_sFilename.Equals(""))
				throw new ArgumentNullException("No Xml file specified");
			
			_lsTracks = new List<AudioFile>();
			
			// Each 'track' node launch an AudioFile creation
			XmlDocument xDoc = new XmlDocument();
			xDoc.Load(_sFilename);
			foreach(XmlNode xNode in xDoc.GetElementsByTagName("track"))
			{
				AudioFile af = new AudioFile();
				af.ReadFromXml(xNode);
				_lsTracks.Add(af);
			}
			
			// Making the parameters by default
			ResetList();
		}
		
		private void SaveTracks(XmlTextWriter xWriter)
		{
			xWriter.WriteStartElement("tracks");
			if (_lsTracks!=null)
			{
				for(int i=0; i<_lsTracks.Count; i++)
					_lsTracks[i].SaveToXml(xWriter);
			}
				
			xWriter.WriteEndElement();
		}
		
		/// <summary>
		/// Reset the list to its starting point
		/// </summary>
		public void ResetList()
		{
			if (_lsTracks.Count>0)
				_iCurrent = 0;
			else
				_iCurrent = -1;
		}
		
		/// <summary>
		/// Get the next AudioFile in the list, and set it
		/// </summary>
		/// <returns>The audiofile, or null if the list is empty or ended</returns>
		public AudioFile Next()
		{
			if (_iCurrent==-1)
				return null;
			
			_iCurrent++;
			
			return Current;
		}
		
		/// <summary>
		/// The Current AudioFile
		/// </summary>
		public AudioFile Current
		{
			get
			{
				if (_iCurrent==-1)
					return null;
				if (_iCurrent>=_lsTracks.Count)
					return null;
				return _lsTracks[_iCurrent];
			}
		}
		
		/// <summary>
		/// Tracks Count
		/// </summary>
		public int CountTracks
		{
			get 
			{
				if (_lsTracks!=null)
					return _lsTracks.Count;
				else
					return 0;
			}
		}
		
		/// <summary>
		/// Add an AudioFile to the list
		/// </summary>
		/// <param name="audioFile">AudioFile to be added</param>
		public void AddTrack(AudioFile audioFile)
		{
			if (_lsTracks==null)
				_lsTracks = new List<AudioFile>();
			_lsTracks.Add(audioFile);
		}
		#endregion
		
		#region Xml Functions
		/// <summary>
		/// Saves the Tracklist in Xml Format
		/// </summary>
		/// <param name="filename">The file to be created</param>
		public void SaveToXml(string filename)
		{
			XmlTextWriter xWriter = new XmlTextWriter(filename, System.Text.Encoding.Unicode);
			xWriter.Formatting = Formatting.Indented;
			xWriter.WriteStartDocument(true);
			xWriter.WriteStartElement("tracklist");
			xWriter.WriteAttributeString("title", _sTitle);
			xWriter.WriteAttributeString("author", _sAuthor);
			xWriter.WriteAttributeString("randomize", _bRandomizeChoice ? "on" : "off");
			xWriter.WriteStartElement("description");
			xWriter.WriteString(_sDescription);
			xWriter.WriteEndElement();
			
			SaveTracks(xWriter);
			
			xWriter.WriteEndElement();
			xWriter.WriteEndDocument();
			xWriter.Flush();
			xWriter.Close();
			
			_sFilename = filename;
		}
		
		/// <summary>
		/// Reads a Xml File to load a Tracklist
		/// </summary>
		/// <param name="filename">The File to be loaded</param>
		/// <returns>Did the loading succeed ?</returns>
		public bool ReadFromXml(string filename)
		{
			_sFilename = filename;
			XmlTextReader xReader = new XmlTextReader(filename);
			try
			{
				if (!xReader.ReadToFollowing("tracklist"))
					return false;

				// Reading the title
				_sTitle = xReader.GetAttribute("title");
				
				// Reading the author name
				_sAuthor = xReader.GetAttribute("author");
				if (_sAuthor==null)
					_sAuthor = "";
				
				// Reading the Randomize choice
				string sRandomize = xReader.GetAttribute("randomize");
				_bRandomizeChoice = ((sRandomize!=null) && (sRandomize=="on"));
				
				// Reading the description
				if (!xReader.ReadToFollowing("description"))
					return false;
				_sDescription = xReader.ReadString();
				
				// Reading end
				xReader.Close();
			}
			catch(Exception)
			{
				return false;
			}
			return true;
		}
		
		#endregion
		
		#region Accessors
		/// <summary>
		/// Tracklist's title
		/// </summary>
		public string Title
		{
			get {return _sTitle;}
			set {_sTitle = value;}
		}
		
		// Tracklist's Description
		public string Description
		{
			get {return _sDescription;}
			set {_sDescription = value;}
		}
		
		/// <summary>
		/// Tracklist's Author
		/// </summary>
		public string Author
		{
			get {return _sAuthor;}
			set {_sAuthor = value;}
		}
		
		/// <summary>
		/// Is the tracklist Randomized by default ?
		/// </summary>
		public bool RandomizeChoice
		{
			get {return _bRandomizeChoice;}
			set {_bRandomizeChoice = value;}
		}
		
		/// <summary>
		/// List of all the Tracks
		/// </summary>
		public List<AudioFile> Tracks
		{
			get {return _lsTracks;}
		}
		#endregion
	
		public override string ToString()
		{
			return _sTitle;
		}
		
		#region Misc Functions
		/// <summary>
		/// Randomize the Tracks
		/// </summary>
		public void Randomize()
		{
			Random random = new Random(Convert.ToInt32(ClockManager.GetTime()));
			// Traversing the list from last to first
			for (int indx=_lsTracks.Count-1; indx>0; indx--)
			{
				// Getting an unplaced element
				int position = random.Next(indx);
				// Switching with the last unplaced element
				AudioFile af = _lsTracks[indx];
				_lsTracks[indx] = _lsTracks[position];
				_lsTracks[position] = af;
			}
		}
		#endregion
		
		#region Static Functions
		/// <summary>
		/// Constructs a Tracklist from a Xml File
		/// </summary>
		/// <param name="filename">The source filename</param>
		/// <returns>The Tracklist</returns>
		public static Tracklist FromFile(string filename)
		{
			Tracklist t = new Tracklist();
			if (t.ReadFromXml(filename))
				return t;
			else
				return null;
		}
		#endregion
		
		#region IListObject interface members
		public Surface GetSurface(Size size)
		{
			// Initializing the background
			Surface sfTemp = new Surface(size);
			sfTemp.Fill(Color.Black);
			sfTemp.Fill(new Rectangle(1,1,size.Width-2, size.Height-2), Color.Goldenrod	);
			// Initializing the text
			Label lblText = new Label(ToString(), 14, Color.Black, TextAlignment.CenterMiddle);
			lblText.Size = sfTemp.Size;
			lblText.Location = new Point(0,0);
			lblText.Init();
			sfTemp.Blit(lblText.Surface, lblText.Location);
			return sfTemp;
		}
		
		public Surface GetSurfaceSelected(Size size)
		{
			// Initializing the background
			Surface sfTemp = new Surface(size);
			sfTemp.Fill(Color.Black);
			sfTemp.Fill(new Rectangle(1,1,size.Width-2, size.Height-2), Color.Sienna);
			// Initializing the text
			Label lblText = new Label(ToString(), 14, Color.Black, TextAlignment.CenterMiddle);
			lblText.Size = sfTemp.Size;
			lblText.Location = new Point(0,0);
			lblText.Init();
			sfTemp.Blit(lblText.Surface, lblText.Location);
			return sfTemp;
		}
		
		public Surface GetSurfaceHovered(Size size)
		{
			// Initializing the background
			Surface sfTemp = new Surface(size);
			sfTemp.Fill(Color.Black);
			sfTemp.Fill(new Rectangle(1,1,size.Width-2, size.Height-2), Color.Chocolate);
			// Initializing the text
			Label lblText = new Label(ToString(), 14, Color.Black, TextAlignment.CenterMiddle);
			lblText.Size = sfTemp.Size;
			lblText.Location = new Point(0,0);
			lblText.Init();
			sfTemp.Blit(lblText.Surface, lblText.Location);
			return sfTemp;
		}
		#endregion
	}
}
